package redis

import (
	"OJCenter/global"
	"errors"
	"fmt"
	"gopkg.in/redis.v3"
	"strconv"
	"time"
)

const (
	redisCreateTimeField = "t"
)

type RedisDao struct {
	RedisCli *redis.Client // 登录专用redis
	TTL      time.Duration
}

func NewRedisDao() (*RedisDao, error) {
	conf := global.Conf.DaoConf.RedisConfig
	rdb := redis.NewClient(&redis.Options{Addr: conf.Addr, Password: conf.Pwd, DB: int64(conf.DB)})
	ttl, _ := time.ParseDuration(conf.TTL)
	dao := &RedisDao{RedisCli: rdb, TTL: ttl}
	_, err := rdb.Ping().Result()
	if err != nil {
		global.Logger.Error(conf.Addr)
		global.Logger.Error(err)
		return nil, err
	}
	return dao, nil
}

func (r *RedisDao) PutMapWithDeadline(key string, value map[string]string) (err error) {
	value[redisCreateTimeField] = strconv.Itoa(int(time.Now().Unix()))
	if err = r.RedisCli.HMSetMap(key, value).Err(); err != nil {
		err = fmt.Errorf("set redis map err: %v", err)
		return
	}
	if err = r.RedisCli.Expire(key, r.TTL).Err(); err != nil {
		err = fmt.Errorf("set redis ttl err: %v", err)
		return
	}
	return
}

func (r *RedisDao) GetMap(key string) (value map[string]string, err error) {
	value, err = r.RedisCli.HGetAllMap(key).Result()
	if err != nil {
		err = fmt.Errorf("get redis map err: %v", err)
		return
	}
	if len(value) == 0 {
		err = errors.New("redis cache is nil")
		return
	}
	return
}

// GetMapWithDeadline 可能有点bug这里
func (r *RedisDao) GetMapWithDeadline(key string, fields ...string) (value map[string]string, err error) {
	vs, err := r.RedisCli.HMGet(key, fields...).Result()
	if err != nil {
		return
	}
	for i, field := range fields {
		if v, ok := vs[i].(string); ok {
			value[field] = v
		}
	}
	if err != nil {
		err = fmt.Errorf("get redis fields err: %v", err)
		value = nil
		return
	}
	ctStr := value[redisCreateTimeField]
	if ctStr == "" {
		err = errors.New("redis cache is nil")
		value = nil
		return
	}
	return
}

func (r *RedisDao) GetString(key string) (string, error) {
	return r.RedisCli.Get(key).Result()
}

func (r *RedisDao) SetString(key string, json string, duration time.Duration) error {
	return r.RedisCli.Set(key, json, duration).Err()
}

func (r *RedisDao) IsKeyAli(key string) (bool, error) {
	return r.RedisCli.Exists(key).Result()
}

func (r *RedisDao) DelKey(key ...string) (int64, error) {
	return r.RedisCli.Del(key...).Result()
}
func (r *RedisDao) SSet(key string, values ...string) (int64, error) {
	return r.RedisCli.SAdd(key, values...).Result()
}

func (r *RedisDao) SDel(key string, values ...string) (int64, error) {
	return r.RedisCli.SRem(key, values...).Result()
}

func (r *RedisDao) SHas(key string, value string) (bool, error) {
	return r.RedisCli.SIsMember(key, value).Result()
}

func (r *RedisDao) SGet(key string) ([]string, error) {
	return r.RedisCli.SMembers(key).Result()
}
